package com.jfm.jfmc.core.icc;

import com.jfm.jfmc.core.config.ApplicationContextHelper;
import com.jfm.jfmc.core.icc.entity.ControlEntity;
import com.jfm.jfmc.core.icc.worker.CollectWorker;
import com.jfm.jfmc.core.icc.worker.CollectWorkerFactory;
import com.jfm.jfmc.core.icc.worker.WorkerPool;
import com.jfm.jfmm.collector.entity.collect.CollectParam;
import com.jfm.jfmm.collector.entity.collect.Param;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author DYang
 * @since 2024-10-22 22:46
 *
 * 任务控制器
 * 对采集任务进行创建、管理、分发、监控
 */
@Slf4j
public class JobControl {

    private static final String JOB_CONTROL = "JMC_JOB_CONTROL";
    // 计数器减少步长
    private static final Integer SETUP = 1;
    // 缓存采集控制器
    private static final List<ControlEntity> controlList;

    private static final WorkerPool workerPool;

    /**
     * 单线程池定时任务
     * 创建定时任务，定时轮询创建采集任务
     */
    private static final ScheduledExecutorService scheduler;
    static {
        controlList = new ArrayList<>(1024);
        scheduler = Executors.newScheduledThreadPool(1, r -> new Thread(r, JOB_CONTROL));
        workerPool = ApplicationContextHelper.getBean(WorkerPool.class);
    }

    /**
     * 初始化任务控制器
     */
    public static void init() {
        initControl();
        // 开启定时任务，1秒执行一次，计数器控制采集器
        scheduler.scheduleAtFixedRate(new JobWorker(), 0, 1, TimeUnit.SECONDS);
    }

    /**
     * 初始化任务控制器
     */
    private static void initControl(){
        // 初始化控制器
        Map<String, CollectParam> collectParamMap = CollectTaskManage.getCollectParamMap();
        if (collectParamMap == null) {
            return;
        }
        collectParamMap.forEach((metricId, collectParam) -> {
            Param param = collectParam.getParam();
            controlList.add(new ControlEntity(metricId, transformFrequency(param.getFrequency(), Param.transformTimeUnit(param.getTimeUnit())),param.isEnabled()));
        });
    }

    /**
     * 停止采集器
     * @param metricId 任务ID
     */
    public static void stopCollectWorker(String metricId) {
        ControlEntity controlEntity = controlList.parallelStream().filter(entity -> metricId.equals(entity.getMetricId())).findFirst().orElse(null);
        if (controlEntity != null) {
            controlEntity.setEnable(false);
        }
    }

    /**
     * 转换采集频率
     * @param frequency 采集频率
     * @param timeUnit 时间单位
     * @return 转换后的采集频率
     */
    private static int transformFrequency(int frequency, TimeUnit timeUnit) {
        if (timeUnit == null) return frequency;

        return switch (timeUnit) {
            case MINUTES -> frequency * 60;
            case HOURS -> frequency * 60 * 60;
            case DAYS -> frequency * 24 * 60 * 60;
            default -> frequency;
        };
    }

    public static void updateCollectFrequency(String metricId, int frequency, TimeUnit unit) {
        Optional<ControlEntity> optional = controlList.parallelStream()
                .filter(entity -> metricId.equals(entity.getMetricId()))
                .findFirst();
        if (optional.isPresent()) {
            ControlEntity entity = optional.get();
            entity.setFrequency(transformFrequency(frequency, unit));
        }

    }


    /**
     * 任务控制器实现者
     * 执行任务，控制采集器采集数据
     */
    private static class JobWorker implements Runnable {

        @Override
        public void run() {
            try {
                long startTime = System.currentTimeMillis();
                for (ControlEntity entity : controlList) {
                    // 减少计数器，当计数器计数<=0时，创建采集器，开始采集数据
                    if (entity.isEnable() && entity.countDown(SETUP)) {
                        CollectWorker worker = CollectWorkerFactory.createWorker(entity.getMetricId());
                        workerPool.executeJob(worker);

                        log.debug("采集任务：{}，采集器创建成功，当前采集任务队列大小为：{}", entity.getMetricId(), workerPool.getActiveCount());
                    }
                }
                log.debug("执行任务耗时 {}",System.currentTimeMillis() - startTime);
            } catch (Exception e) {
                log.error("采集控制器执行异常", e);
            }
        }

    }

}
